use std::sync::{Arc, Mutex};
use crate::context::Context;
use crate::message::Message;
use crate::actors::Actor;
use crate::mailbox::flume_mailbox::FlumeMailbox;
use crate::mailbox::crossbeam_mailbox::CrossbeamMailbox;
use crate::mailbox::tokio_mailbox::TokioMailbox;

pub enum MailboxType {
    Unbounded,
    Bounded(usize),
}

pub enum QueueType {
    Flume,
    Crossbeam,
    Tokio,
}

pub struct Mailbox {
    sender: Box<dyn MailboxSender>,
}

impl Mailbox {
    pub fn new(actor: Arc<Mutex<dyn Actor + Send>>, mailbox_type: MailboxType, queue_type: QueueType) -> Self {
        match queue_type {
            QueueType::Flume => {
                let mailbox = FlumeMailbox::new(actor, mailbox_type);
                Mailbox { sender: Box::new(mailbox) }
            }
            QueueType::Crossbeam => {
                let mailbox = CrossbeamMailbox::new(actor, mailbox_type);
                Mailbox { sender: Box::new(mailbox) }
            }
            QueueType::Tokio => {
                let mailbox = TokioMailbox::new(actor, mailbox_type);
                Mailbox { sender: Box::new(mailbox) }
            }
        }
    }

    pub async fn send(&self, msg: Box<dyn Message>) {
        self.sender.send(msg).await;
    }
}

pub trait MailboxSender: Send + Sync {
    fn send(&self, msg: Box<dyn Message>) -> BoxFuture<'static, ()>;
}

pub mod flume_mailbox;
pub mod crossbeam_mailbox;
pub mod tokio_mailbox;